﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using SimpleXMLParser;
using System.Collections;
using System.Threading;

namespace FileParser
{
    /// <summary>
    /// 
    /// </summary>
    class C_SVNInterface
    {
        private string address;
        private int revisions;
        private string name;
        Thread executingThread;
        bool basis;
        string outLoc;

        public const string REVSTR = "Last Changed Rev: ";

        /// <summary>
        /// 
        /// </summary>
        /// <param name="iadd"></param>
        /// <param name="iname"></param>
        public C_SVNInterface(string iadd, string iname)
        {
            address = iadd;
            name = iname;
            revisions = -1;
            basis = false;

            outLoc = Path.GetDirectoryName(
                System.Reflection.Assembly.GetExecutingAssembly()
                .GetName().CodeBase).Substring(6);

            (executingThread = new Thread(GetRevision)).Start();
        }

        /// <summary>
        /// 
        /// </summary>
        public void Close()
        {
            if(executingThread.IsAlive)
                executingThread.Abort();

            CleanUp(true, 3);
        }

        /// <summary>
        /// This cleans up the results of parsing the information from the SVN server,
        /// which creates several directories in the process. Ther eis some chance
        /// that there can be issues with the deletion depending on the programs
        /// that a user's computer is running, so it only attempts to delete
        /// a set number of times.
        /// </summary>
        /// <param name="deleteSVN">
        /// A boolean on whether or not the SVN folder, which subversion outputs
        /// its information to, should attempt to be deleted. It some implementations
        /// this was more important.
        /// </param>
        /// <param name="tries">
        /// The number of times that the program should try to delete the
        /// the information before giving up (sometimes it can have a concurrent
        /// access due a writer closing slowly, and this makes a difference)
        /// </param>
        private void CleanUp(bool deleteSVN, int tries)
        {
            while ((deleteSVN && Directory.Exists(outLoc + "\\SVN") || Directory.Exists(outLoc + "\\xml"))
                && tries > 0)
            {
                try
                {
                    if (Directory.Exists(outLoc + "\\xml"))
                        Directory.Delete(outLoc + "\\xml", true);
                    if(deleteSVN) 
                        Directory.Delete(outLoc + "\\SVN", true);
                }
                catch
                {
                    System.Threading.Thread.Sleep(100);
                    tries--;
                }
            }
        }

        /// <summary>
        /// Returns the number of revisions that a SVN repository has.
        /// May take some time to resolve if SVN has just been created.
        /// </summary>
        /// <returns>
        /// An integer representing the number of revisions an SVN
        /// repository has reported in the SVN info command.
        /// </returns>
        public int GetRevs()
        {
            //This is for external accessors, in case that the
            // constructor hasn't caught up to where the upper
            // program is calling it. Should add a timeout here
            // perhaps.
            while (revisions == -1)
                Thread.Sleep(200);

            return revisions;
        }

        /// <summary>
        /// Getter for the addess being used to get SVN information from.
        /// </summary>
        /// <returns>
        /// The address, as a string
        /// </returns>
        public string GetLoc()
        {
            return address;
        }

        //Process a revision, doing all the magic on it.
        // will eventually return the chosen data type
        // that can be used to creates graphics/animation.
        public C_DataStructure[] ProcessRevision(int rev)
        {
            //This is for external accessors, in case that the
            // constructor hasn't caught up to where the upper
            // program is calling it. Should add a timeout here
            // perhaps.
            while (revisions == -1)
                Thread.Sleep(200);

            if (rev < 0 || rev > revisions)
                return null;

            //Clean up to reduce memory footprint, and also beacuse if the files
            // aren't empty, it breaks the process sadface

            
            if(!basis)
                CleanUp(true, 3);

            basis = true;

            System.Diagnostics.Debug.WriteLine("Proc DB: outLoc - " + outLoc);
            System.Diagnostics.Debug.WriteLine("svn export -r " + rev + " " + address + " SVN");

            C_CMDUtil.CMDCommand("svn export -r " + rev + " " + address + " SVN",-1);

            System.Diagnostics.Debug.WriteLine("Finished checkout, processing");

            C_DoxyFile.GenDConfig(name, outLoc + "\\SVN");

            C_CMDUtil.CMDCommand("doxygen DoxyFile", -1);

            File.Delete("DoxyFile");

            //XML PARSING GOES HERE MMKAY
            ArrayList ret = new C_XmlParser(outLoc + "\\xml\\").GenerateData();

            //Clean up to reduce memory footprint, and also beacuse if the files
            // aren't empty, it breaks the process sadface

            CleanUp(true, 3);

            return (C_DataStructure[]) ret.ToArray(typeof(C_DataStructure));
        }

        /// <summary>
        /// Run svn info using the CMD emulator, storing it to a temporary
        /// file to parse the info from, focusing on just the revisons.
        /// </summary>
        private void GetRevision()
        { 
            //Warning: The redirect symbol used here (>) may not work on
            // non-windows systems! (But it works in Linux and and Mac )
            if (!C_CMDUtil.CMDCommand("svn info " + address + " > tmp.txt", 15000))
            {
                revisions = 0;
                return;
            }

            List<string> textList = new List<string>();

            //Read the output of the CMD from tmp.txt
            StreamReader reader = new StreamReader("tmp.txt");
            try
            {
                do
                {
                    textList.Add(reader.ReadLine());
                }
                while (reader.Peek() != -1);
            }

            catch
            {
                textList.Add("File is empty");
            }

            finally
            {
                reader.Close();
                File.Delete("tmp.txt");
            }

            string revLine = "";

            //Go through all the lines read and find the revisions file
            foreach (string line in textList)
            {
                if(line.StartsWith(REVSTR))
                    revLine = line;
                
                System.Diagnostics.Debug.WriteLine(line);
            }

            //If the string size is nothing,
            // then the revision wasn't found
            if (revLine.Length == 0)
            {
                revisions = 0;
                return;
            }

            System.Diagnostics.Debug.WriteLine("Rev found? : " + revLine);

            //Remove the revstring
            revLine = revLine.Replace(REVSTR, "");

            revisions = int.Parse(revLine.Trim());
        }
    }
}
